package com.airbnb.airpal.resources; import com.airbnb.airpal.api.Job; import com.airbnb.airpal.api.JobState; import com.airbnb.airpal.api.queries.CreateSavedQueryBuilder; import com.airbnb.airpal.api.queries.SavedQuery; import com.airbnb.airpal.api.queries.UserSavedQuery; import com.airbnb.airpal.core.AirpalUser; import com.airbnb.airpal.core.AuthorizationUtil; import com.airbnb.airpal.core.store.history.JobHistoryStore; import com.airbnb.airpal.core.store.queries.QueryStore; import com.airbnb.airpal.presto.PartitionedTable; import com.airbnb.airpal.presto.Table; import com.facebook.presto.client.Column; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Ordering; import com.google.inject.Inject; import org.joda.time.DateTime; import org.secnod.shiro.jaxrs.Auth; import javax.annotation.Nullable; import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; @Path("/api/query") public class QueryResource { private final JobHistoryStore jobHistoryStore; private final QueryStore queryStore; @Inject public QueryResource(JobHistoryStore jobHistoryStore, QueryStore queryStore) { this.jobHistoryStore = jobHistoryStore; this.queryStore = queryStore; } @GET @Path("saved") @Produces(MediaType.APPLICATION_JSON) public Response getSaved( @Auth AirpalUser user, @QueryParam("table") List<PartitionedTable> tables) { if (user != null) { return Response.ok(queryStore.getSavedQueries(user)).build(); } return Response.ok(Collections.<SavedQuery>emptyList()).build(); } @POST @Path("saved") @Produces(MediaType.APPLICATION_JSON) public Response saveQuery( @Auth AirpalUser user, @FormParam("description") String description, @FormParam("name") String name, @FormParam("query") String query) { CreateSavedQueryBuilder createFeaturedQueryRequest = CreateSavedQueryBuilder.featured() .description(description) .name(name) .query(query); if (user != null) { SavedQuery savedQuery = createFeaturedQueryRequest.user(user.getUserName()) .build(); if (queryStore.saveQuery((UserSavedQuery) savedQuery)) { return Response.ok(savedQuery.getUuid()).build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } } return Response.status(Response.Status.UNAUTHORIZED).build(); } @DELETE @Path("saved/{uuid}") @Produces(MediaType.APPLICATION_JSON) public Response deleteQuery( @Auth AirpalUser user, @PathParam("uuid") UUID uuid) { if (user != null) { if (queryStore.deleteSavedQuery(user, uuid)) { return Response.status(Response.Status.NO_CONTENT).build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } } return Response.status(Response.Status.UNAUTHORIZED).build(); } public static Function<Job, DateTime> JOB_ORDERING = new Function<Job, DateTime>() { @Nullable @Override public DateTime apply(@Nullable Job input) { if (input == null) { return null; } return input.getQueryFinished(); } }; @GET @Path("history") @Produces(MediaType.APPLICATION_JSON) public Response getHistory( @Auth AirpalUser user, @QueryParam("table") List<Table> tables) { Iterable<Job> recentlyRun; if (tables.size() < 1) { recentlyRun = jobHistoryStore.getRecentlyRun(200); } else { Table[] tablesArray = tables.toArray(new Table[tables.size()]); Table[] restTables = Arrays.copyOfRange(tablesArray, 1, tablesArray.length); recentlyRun = jobHistoryStore.getRecentlyRun(200, tablesArray[0], restTables); } ImmutableList.Builder<Job> filtered = ImmutableList.builder(); for (Job job : recentlyRun) { if (job.getTablesUsed().isEmpty() && (job.getState() == JobState.FAILED)) { filtered.add(job); continue; } for (Table table : job.getTablesUsed()) { if (AuthorizationUtil.isAuthorizedRead(user, table)) { filtered.add(new Job( job.getUser(), job.getQuery(), job.getUuid(), job.getOutput(), job.getQueryStats(), job.getState(), Collections.<Column>emptyList(), Collections.<Table>emptySet(), job.getQueryStartedDateTime(), job.getError(), job.getQueryFinishedDateTime())); } } } List<Job> sortedResult = Ordering .natural() .nullsLast() .onResultOf(JOB_ORDERING) .reverse() .immutableSortedCopy(filtered.build()); return Response.ok(sortedResult).build(); } }